﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Tecnosop.Dominio;
using Tecnosop.WebUI.Models;
using Tecnosop.WebUI.Infrastructure.Notification;
using System.Web.UI;

namespace Tecnosop.WebUI.Controllers
{
    [Authorize]
    public partial class FacturasController : Controller
    {
        private Entidades db = new Entidades();

        #region CRUD

        public virtual ActionResult Index()
        {
            return View(db.FACTURA.ToList());
        }

        public virtual ActionResult Details()
        {
            return View();
        }

        public virtual ActionResult Create(bool error = false)
        {
            try
            {

                DateTime ultima_mod = db.PARAMETROS.Max(p => p.ULTIMA_MODIFICACION_UF);//OrderByDescending(p => p.ULTIMA_MODIFICACION_UF).First();
                if (DateTime.Today > ultima_mod)
                {
                    this.ShowMessage(MessageType.Warning, "Debe modificar el valor de la UF para hoy día antes de facturar");
                    return RedirectToAction(Actions.ActualizarUF());
                }
            }
            catch (InvalidOperationException)
            {
                this.ShowMessage(MessageType.Warning, "Debe modificar el valor de la UF para hoy día antes de facturar");
                return RedirectToAction(Actions.ActualizarUF());
            }

            

            ViewBag.NombresClientes = db.CLIENTE.Select(c => c.NOMBRE).ToList();
            ViewBag.RutsClientes = db.CLIENTE.Select(c => c.RUT_CLIENTE).ToList();

            if (error)
            {
                this.ShowMessage(MessageType.Error, "Ocurrió un error al tratar de crear la factura");
            }

            return View();
        }

        [HttpPost]
        public virtual ActionResult Create(CreateFacturaStep1ViewModel createFacturaVM)
        {
            ViewBag.NombresClientes = db.CLIENTE.Select(c => c.NOMBRE).ToList();
            ViewBag.RutsClientes = db.CLIENTE.Select(c => c.RUT_CLIENTE).ToList();

            if (ModelState.IsValid)
            {
                try
                {
                    if (String.IsNullOrWhiteSpace(createFacturaVM.RutCliente) && String.IsNullOrWhiteSpace(createFacturaVM.NombreCliente))
                    {
                        ModelState.AddModelError("", "Ingrese al menos uno de los campos.");
                        ModelState.AddModelError("RutCliente", " ");
                        ModelState.AddModelError("NombreCliente", " ");

                        return View();
                    }

                    if (createFacturaVM.RutCliente == null)
                    {
                        createFacturaVM.RutCliente = db.CLIENTE.Single(c => c.NOMBRE.Equals(createFacturaVM.NombreCliente)).RUT_CLIENTE;
                    }

                    if (createFacturaVM.EsFacturaConvenio)
                    {
                        int numConvenios = db.CONVENIO.Count(c => c.RUT_CLIENTE.Equals(createFacturaVM.RutCliente) && (c.CONVENIO_VIGENTE ?? false));
                        if (numConvenios == 0)
                        {
                            this.ShowMessage(MessageType.Warning, "Corrobore la información ingresada. Si la información del cliente es incorrecta, revise el estado de sus convenios.");
                            ModelState.AddModelError("", "El cliente ingresado no tiene ningún convenio vigente.");
                            return View();
                        }
                    }

                    FACTURA factura = new FACTURA
                    {
                        NUMERO_FACTURA = createFacturaVM.NumeroFactura,
                        RAZON_SOCIAL = createFacturaVM.EsRazonSocialTecnosop ? "Comercializadora Tecnosop" : "Juan Carlos Maldonado Huerta",
                        FECHA_INSTALACION = DateTime.Today,
                        FACTURA_EMITIDA = false,
                        NULA = false,
                        DESCUENTO = 0,
                        TOTAL = 0
                    };

                    db.FACTURA.Add(factura);
                    db.SaveChanges();

                    return RedirectToAction(createFacturaVM.EsFacturaConvenio
                            ? MVC.FacturaConvenio.Create(factura.NUMERO_FACTURA, createFacturaVM.EsRazonSocialTecnosop, createFacturaVM.RutCliente)
                            : MVC.FacturaVentaDirecta.Create(factura.NUMERO_FACTURA, createFacturaVM.EsRazonSocialTecnosop, createFacturaVM.RutCliente));
                }
                catch
                {
                    return View();
                }
            }
            else
            {
                return View();
            }
        }

        public virtual ActionResult ActualizarUF()
        {
            return View();
        }

        [HttpPost]
        public virtual ActionResult ActualizarUF(ActualizarUFViewModel UFVM)
        {
            PARAMETROS parms = new PARAMETROS
            {
                VALOR_UF = UFVM.ValorUF,
                ULTIMA_MODIFICACION_UF = DateTime.Today
            };

            db.PARAMETROS.Add(parms);
            db.SaveChanges();

            return RedirectToAction(Actions.Create(error: false));
        }

        [HttpPost]
        public virtual ActionResult Delete(int id, string RAZON_SOCIAL)
        {
            try
            {
                FACTURA factura = db.FACTURA.Find(id, RAZON_SOCIAL);

                if (factura.FACTURA_EMITIDA ?? false)
                {
                    this.ShowMessage(MessageType.Error, "No se puede eliminar una factura emitida.");
                    return RedirectToAction(Actions.Index());
                }

                db.FACTURA.Remove(factura);
                db.SaveChanges();
                this.ShowMessage(MessageType.Success, "Se eliminó la factura N°: " + id + " de la base de datos.");
            }
            catch
            {
                this.ShowMessage(MessageType.Error, "No se pudo eliminar la factura N°: " + id + " de la base de datos.");
            } 

            return RedirectToAction(Actions.Index());
        }

        #endregion

        #region Busqueda

        [ChildActionOnly]
        public virtual ActionResult Search()
        {
            return PartialView();
        }

        public virtual ActionResult Busqueda()
        {
            return View();
        }

        public virtual ActionResult ResultadoBusqueda(string Criterios, string AreaBusqueda)
        {
            switch (Criterios)
            {
                case "NumeroFactura":
                    int numero;
                    return View(new ResultadoBusquedaFacturaViewModel
                    {
                        Resultado = Int32.TryParse(AreaBusqueda, out numero)
                                    ? db.FACTURA.Where(f => f.NUMERO_FACTURA == numero).ToList()
                                    : new List<FACTURA>(),
                        CriterioParaOrdenar = Criterios

                    });
                case "NombreCliente":
                    IEnumerable<FACTURA> resultadoNombre = new List<FACTURA>();
                    var facturasVDNombre = db.FACTURA_VENTA_DIRECTA
                                               .Where(f => f.CLIENTE.NOMBRE.Contains(AreaBusqueda))
                                               .Select(f => f.FACTURA).ToList();

                    var facturasConvenioNombre = db.FACTURA_CONVENIO
                                                     .Where(f => f.CONVENIO.CLIENTE.NOMBRE.Contains(AreaBusqueda))
                                                     .Select(f => f.FACTURA).ToList();
                    
                    resultadoNombre = resultadoNombre.Concat(facturasConvenioNombre);
                    resultadoNombre = resultadoNombre.Concat(facturasVDNombre);

                    return View(new ResultadoBusquedaFacturaViewModel
                    {
                        Resultado = resultadoNombre,
                        CriterioParaOrdenar = Criterios
                    });
                case "RutCliente":
                    IEnumerable<FACTURA> resultadoRut = new List<FACTURA>();
                    var facturasVDRut = db.FACTURA_VENTA_DIRECTA
                                            .Where(f => f.CLIENTE.RUT_CLIENTE.Equals(AreaBusqueda))
                                            .Select(f => f.FACTURA).ToList();

                    var facturasConvenioRut = db.FACTURA_CONVENIO
                                                .Where(f => f.CONVENIO.CLIENTE.RUT_CLIENTE.Equals(AreaBusqueda))
                                                .Select(f => f.FACTURA).ToList();
                    
                    resultadoRut = resultadoRut.Concat(facturasConvenioRut);
                    resultadoRut = resultadoRut.Concat(facturasVDRut);

                    return View(new ResultadoBusquedaFacturaViewModel
                    {
                        Resultado = resultadoRut,
                        CriterioParaOrdenar = Criterios
                    });
                case "NumeroConvenio":
                    int numeroConvenio;
                    return View(new ResultadoBusquedaFacturaViewModel
                    {
                        Resultado = Int32.TryParse(AreaBusqueda, out numeroConvenio)
                                    ? db.FACTURA_CONVENIO.Where(f => f.NUMERO_CONVENIO == numeroConvenio).Select(f => f.FACTURA).ToList()
                                    : new List<FACTURA>(),
                        CriterioParaOrdenar = Criterios
                    });
                default:
                    return PartialView(Views.Search);
            }
        }

        public virtual ActionResult BusquedaAvanzada()
        {
            return View();
        }

        [HttpPost]
        public virtual ActionResult ResultadoBusquedaAvanzada(BusquedaAvanzadaFacturaViewModel model/*string Criterios, string AreaBusqueda, DateTime FechaInicio, DateTime FechaFinal*/)
        {
            if (String.IsNullOrEmpty(model.AreaBusqueda))
            {
                return View(new ResultadoBusquedaAvanzadaFacturaViewModel
                    {
                        Resultado = db.FACTURA.Where(f => f.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                       && f.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0).ToList(),
                        CriterioParaOrdenar = model.Criterios.ToString(),
                        FechaInicio = model.FechaInicio,
                        FechaFinal = model.FechaFinal,
                        AreaBusqueda = ""
                    });
            }

            switch (model.Criterios.ToString())
            {
                case "NumeroFactura":
                    int numero;

                    return View(new ResultadoBusquedaAvanzadaFacturaViewModel
                    {
                        Resultado = Int32.TryParse(model.AreaBusqueda, out numero)
                                    ? db.FACTURA.Where(f => f.NUMERO_FACTURA == numero
                                                       && f.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                       && f.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0).ToList()
                                    : new List<FACTURA>(),
                        CriterioParaOrdenar = model.Criterios.ToString(),
                        FechaInicio = model.FechaInicio,
                        FechaFinal = model.FechaFinal,
                        AreaBusqueda = model.AreaBusqueda
                    });
                case "NombreCliente":
                    IEnumerable<FACTURA> resultadoNombre = new List<FACTURA>();
                    var facturasVDNombre = db.FACTURA_VENTA_DIRECTA
                                               .Where(f => f.CLIENTE.NOMBRE.Contains(model.AreaBusqueda)
                                                      && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                      && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0)
                                               .Select(f => f.FACTURA).ToList();

                    var facturasConvenioNombre = db.FACTURA_CONVENIO
                                                     .Where(f => f.CONVENIO.CLIENTE.NOMBRE.Contains(model.AreaBusqueda)
                                                            && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                            && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0)
                                                     .Select(f => f.FACTURA).ToList();

                    resultadoNombre = resultadoNombre.Concat(facturasConvenioNombre);
                    resultadoNombre = resultadoNombre.Concat(facturasVDNombre);

                    return View(new ResultadoBusquedaAvanzadaFacturaViewModel
                    {
                        Resultado = resultadoNombre,
                        CriterioParaOrdenar = model.Criterios.ToString(),
                        FechaInicio = model.FechaInicio,
                        FechaFinal = model.FechaFinal,
                        AreaBusqueda = model.AreaBusqueda
                    });
                case "RutCliente":
                    IEnumerable<FACTURA> resultadoRut = new List<FACTURA>();
                    var facturasVDRut = db.FACTURA_VENTA_DIRECTA
                                            .Where(f => f.CLIENTE.RUT_CLIENTE.Equals(model.AreaBusqueda)
                                                   && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                   && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0)
                                            .Select(f => f.FACTURA).ToList();

                    var facturasConvenioRut = db.FACTURA_CONVENIO
                                                .Where(f => f.CONVENIO.CLIENTE.RUT_CLIENTE.Equals(model.AreaBusqueda)
                                                       && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                                       && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0)
                                                .Select(f => f.FACTURA).ToList();

                    resultadoRut = resultadoRut.Concat(facturasConvenioRut);
                    resultadoRut = resultadoRut.Concat(facturasVDRut);

                    return View(new ResultadoBusquedaAvanzadaFacturaViewModel
                    {
                        Resultado = resultadoRut,
                        CriterioParaOrdenar = model.Criterios.ToString(),
                        FechaInicio = model.FechaInicio,
                        FechaFinal = model.FechaFinal,
                        AreaBusqueda = model.AreaBusqueda
                    });
                case "NumeroConvenio":
                    int numeroConvenio;
                    return View(new ResultadoBusquedaAvanzadaFacturaViewModel
                    {
                        Resultado = Int32.TryParse(model.AreaBusqueda, out numeroConvenio)
                                    ? db.FACTURA_CONVENIO
                                        .Where(f => f.NUMERO_CONVENIO == numeroConvenio
                                               && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaInicio) > 0
                                               && f.FACTURA.FECHA_INSTALACION.Value.CompareTo(model.FechaFinal) < 0)
                                        .Select(f => f.FACTURA).ToList()
                                    : new List<FACTURA>(),
                        CriterioParaOrdenar = model.Criterios.ToString(),
                        FechaInicio = model.FechaInicio,
                        FechaFinal = model.FechaFinal,
                        AreaBusqueda = model.AreaBusqueda
                    });
                default:
                    return PartialView(Views.Search);
            }
        }

        #endregion

        #region Validaciones

        [OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
        public virtual JsonResult ValidaNumeroFacturaUnico(int NumeroFactura, bool? EsRazonSocialTecnosop)
        {
            if (EsRazonSocialTecnosop.HasValue)
            {
                string razon = EsRazonSocialTecnosop.Value ? "Comercializadora Tecnosop" : "Juan Carlos Maldonado Huerta";
                return !db.FACTURA.Any(f => f.NUMERO_FACTURA == NumeroFactura && f.RAZON_SOCIAL.Equals(razon))
                    ? Json(true, JsonRequestBehavior.AllowGet)
                    : Json("El número de factura ingresado ya fue ocupado para otra factura.", JsonRequestBehavior.AllowGet);
            }
            else
            {
                return Json("Ingrese una razón social.", JsonRequestBehavior.AllowGet);
            }
        }

        [OutputCache(Location = OutputCacheLocation.None, NoStore = true)]
        public virtual JsonResult ValidaBusquedaVacia(string Criterios, string AreaBusqueda)
        {
            switch (Criterios)
            {
                case "NumeroFactura":
                    int numero;

                    return Json(Int32.TryParse(AreaBusqueda, out numero)
                                ? db.FACTURA.Any(f => f.NUMERO_FACTURA == numero)
                                : false, JsonRequestBehavior.AllowGet);
                case "NombreCliente":
                    bool hayFacturasVD = db.FACTURA_VENTA_DIRECTA.Any(f => f.CLIENTE.NOMBRE.Contains(AreaBusqueda));
                    bool hayFacturasConvenio = db.FACTURA_CONVENIO.Any(f => f.CONVENIO.CLIENTE.NOMBRE.Contains(AreaBusqueda));

                    return Json(hayFacturasConvenio || hayFacturasVD, JsonRequestBehavior.AllowGet);
                case "RutCliente":
                    bool hayFacturasVDRut = db.FACTURA_VENTA_DIRECTA.Any(f => f.CLIENTE.RUT_CLIENTE.Equals(AreaBusqueda));
                    bool hayFacturasConvenioRut = db.FACTURA_CONVENIO.Any(f => f.CONVENIO.CLIENTE.RUT_CLIENTE.Equals(AreaBusqueda));

                    return Json(hayFacturasVDRut || hayFacturasConvenioRut, JsonRequestBehavior.AllowGet);
                case "NumeroConvenio":
                    int numeroConvenio;

                    return Json(Int32.TryParse(AreaBusqueda, out numeroConvenio)
                                ? db.FACTURA_CONVENIO.Any(f => f.CONVENIO.NUMERO_CONVENIO == numeroConvenio)
                                : false, JsonRequestBehavior.AllowGet);
                default:
                    return Json(false, JsonRequestBehavior.AllowGet);
            }
        }

        #endregion

        public virtual ActionResult AnularFactura(int NUMERO_FACTURA, string RAZON_SOCIAL)
        {
            FACTURA factura = db.FACTURA.Find(NUMERO_FACTURA, RAZON_SOCIAL);
            factura.NULA = true;
            db.Entry(factura).State = System.Data.EntityState.Modified;
            db.SaveChanges();

            return RedirectToAction(Actions.Index());
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}
